package data;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;

import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartDocument;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

import model.Activity;
import model.Workout;

/**
 * 
 * Reads/Writes to the Workout database. 
 * @author Roman Pusec, Dennis Goldfinger, Marko Bilic
 *
 */
public class WorkoutDao implements IDao<Workout> {

	private String filepath;
	static final String WORKOUTS = "workouts";
	static final String WORKOUT = "workout";
	static final String EXERCISE = "exercise";
	static final String QUANTITY = "quantity";
	static final String NAME = "name";
	static final String EXERCISENAME = "exerciseName";
	
	/**
	 * Constructor which specifies the path to the database. 
	 * @param filepath The path to the database. 
	 */
	public WorkoutDao(String filepath)
	{
		this.filepath = filepath;
	}
    
	/**
	 * Gets all of the Workouts from the database. 
	 */
	@Override
	public ArrayList<Workout> getAll() {

	    ArrayList<Workout> items = new ArrayList<Workout>();
	    try {
	    	// First, create a new XMLInputFactory
	        XMLInputFactory inputFactory = XMLInputFactory.newInstance();
	        // Setup a new eventReader
	        InputStream in = new FileInputStream(filepath); 
	        XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
	        // read the XML document
	        Workout workout = null;
	        Activity tempExercise = null; 
	        int tempQuantity = 0;

	        while (eventReader.hasNext()) 
	        {
	        	XMLEvent event = eventReader.nextEvent();

		        if (event.isStartElement()) 
		        {
		        	StartElement startElement = event.asStartElement();
		            // If we have an item element, we create a new item
		            if (startElement.getName().getLocalPart() == (WORKOUT)) 
		            {
		        	    workout = new Workout("");
		            }
	   
					if (event.asStartElement().getName().getLocalPart().equals(NAME)) 
					{
					    event = eventReader.nextEvent();
					    workout.setName(event.asCharacters().getData());
					    continue;
					}
		          
		            if (event.asStartElement().getName().getLocalPart().equals(EXERCISENAME)) 
		            {
		                event = eventReader.nextEvent();
		                tempExercise = new Activity(event.asCharacters().getData());
		                continue;
		            }
		          
		            if (event.asStartElement().getName().getLocalPart().equals(QUANTITY)) 
		            {
			            event = eventReader.nextEvent();
			            tempQuantity = Integer.parseInt(event.asCharacters().getData());
			            
			            if(tempExercise != null && tempQuantity > 0)
			            {
			            	workout.addExercise(tempExercise, tempQuantity);
			            	tempExercise = null;
			            	tempQuantity = 0;
			            }
			            
			            continue;
		            }
		        }
		        // If we reach the end of an item element, we add it to the list
		        if (event.isEndElement()) 
		        {
		            EndElement endElement = event.asEndElement();
		            if (endElement.getName().getLocalPart() == (WORKOUT)) 
		            {
		            	items.add(workout);
		            }
		        }
	        
		    }
	    } catch (FileNotFoundException e) {
	      e.printStackTrace();
	    } catch (XMLStreamException e) {
	      e.printStackTrace();
	    }
	    return items;
	}
	
	/**
	 * Writes all of the Workouts to the database. 
	 */
	@Override
	public void writeAll(ArrayList<Workout> WorkoutArr) throws Exception {
		
		// create an XMLOutputFactory
	    XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
	    // create XMLEventWriter
	    XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(new FileOutputStream(filepath));
	    // create an EventFactory
	    XMLEventFactory eventFactory = XMLEventFactory.newInstance();
	    XMLEvent end = eventFactory.createDTD("\n");
	    XMLEvent tab = eventFactory.createDTD("\t");
	    // create and write Start Tag
	    StartDocument startDocument = eventFactory.createStartDocument();
	    eventWriter.add(startDocument);

	    // create config open tag
	    eventWriter.add(end);
	    StartElement itemsStartElement = eventFactory.createStartElement("", "", WORKOUTS);
	    eventWriter.add(itemsStartElement);
	    eventWriter.add(end);
	    
	    for(Workout recipe : WorkoutArr)
	    {
	    	StartElement singleItemStartElement = eventFactory.createStartElement("", "", WORKOUT);
	    	eventWriter.add(tab);
	    	eventWriter.add(singleItemStartElement);
	    	eventWriter.add(end);
	    	
	    	// Write the different nodes
		    createNode(eventWriter, NAME, recipe.getName(), eventFactory.createDTD("\t\t"));
		    
		    HashMap<Activity, Integer> foodMap = recipe.getActivities();
		    Object[] keys = foodMap.keySet().toArray();
			Object[] values = foodMap.values().toArray();
			
			for(int i = 0; i < foodMap.size(); i++)
			{
				eventWriter.add(tab);
				eventWriter.add(tab);
				eventWriter.add(eventFactory.createStartElement("", "", EXERCISE));
				eventWriter.add(end);
				createNode(eventWriter, EXERCISENAME, ((Activity)keys[i]).getName(), eventFactory.createDTD("\t\t\t"));
				createNode(eventWriter, QUANTITY, values[i].toString(), eventFactory.createDTD("\t\t\t"));
				eventWriter.add(tab);
				eventWriter.add(tab);
				eventWriter.add(eventFactory.createEndElement("", "", EXERCISE));
				eventWriter.add(end);
			}
		    
		    eventWriter.add(tab);
		    eventWriter.add(eventFactory.createEndElement("", "", WORKOUT));
		    eventWriter.add(end);
	    }
	    
	    eventWriter.add(eventFactory.createEndElement("", "", WORKOUTS));
	    eventWriter.add(end);
	    eventWriter.add(eventFactory.createEndDocument());
	    eventWriter.close();
		
	}
	
	/**
	 * Creates a node in the XML file. 
	 * @param eventWriter The event writer. 
	 * @param name The name of the node. 
	 * @param value The value of the node. 
	 * @throws XMLStreamException 
	 */
	private void createNode(XMLEventWriter eventWriter, String name, String value, XMLEvent tab) throws XMLStreamException 
	{	
	    XMLEventFactory eventFactory = XMLEventFactory.newInstance();
	    XMLEvent end = eventFactory.createDTD("\n");
	    // create Start node
	    StartElement sElement = eventFactory.createStartElement("", "", name);
	    eventWriter.add(tab);
	    eventWriter.add(sElement);
	    // create Content
	    Characters characters = eventFactory.createCharacters(value);
	    eventWriter.add(characters);
	    // create End node
	    EndElement eElement = eventFactory.createEndElement("", "", name);
	    eventWriter.add(eElement);
	    eventWriter.add(end);	
	}


}
